package io.github.ali.commons.validation;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.ParameterNameDiscoverer;

import io.github.ali.commons.log.holder.BizLoggerHolder;
import org.springframework.core.PrioritizedParameterNameDiscoverer;

/**
 * 验证注解处理
 * 
 * @author fuli
 * @version 1.0
 * @date 2017-12-15 13:35
 */
@Aspect
public class ValidationAspect implements BizLoggerHolder {
	private ValidateRender validateRender;
	private ParameterNameDiscoverer parameterNameDiscoverer;

	public ValidationAspect(ValidateRender validateRender,PrioritizedParameterNameDiscoverer parameterNameDiscoverer) {
		this.validateRender = validateRender;
		this.parameterNameDiscoverer = parameterNameDiscoverer;
	}

	@Pointcut("@annotation(io.github.ali.commons.validation.RequireValidate) || @within(io.github.ali.commons.validation.RequireValidate)")
	public void handleValidation() {
	}

	@Around("handleValidation()")
	public Object handleBizException(ProceedingJoinPoint pJoinPoint) throws Throwable {
		Object[] args = pJoinPoint.getArgs();
		if (args.length > 0) {
			MethodSignature methodSignature = (MethodSignature) pJoinPoint.getSignature();
			Method method = methodSignature.getMethod();
			if (method.getDeclaredAnnotation(SkipValidate.class) == null) {
				RequireValidate requireValidate = method.getDeclaredAnnotation(RequireValidate.class);
				if (requireValidate == null) {
					requireValidate = (RequireValidate) methodSignature.getDeclaringType().getAnnotation(RequireValidate.class);
				}
				String[] paramNames = requireValidate.paramNames();
				if (paramNames.length > 0) {
					//尝试从字节码中获取参数名称。如果无法获取，它会使用 ASM 库来分析类文件，并尝试从字节码中提取参数名
					//ParameterNameDiscoverer pnd = new LocalVariableTableParameterNameDiscoverer();
					//DefaultParameterNameDiscoverer替换LocalVariableTableParameterNameDiscoverer
					String[] argsName = parameterNameDiscoverer.getParameterNames(method);
					OUTER: for (int i = 0; i < paramNames.length; i++) {
						for (int j = 0; j < argsName.length; j++) {
							if (argsName[j].equals(paramNames[i])) {
								ParamsValidator.validate(args[j], validateRender);
								continue OUTER;
							}
						}
					}
				} else {
					// 默认检查第一个参数
					ParamsValidator.validate(args[0], validateRender);
				}
			}
		}
		try {
			return pJoinPoint.proceed(args);
		} catch (Exception e) {
			throw e;
		}
	}
}
